# -*- coding: utf-8 -*-

# === メッセージ管理用モデル
class Message < ActiveRecord::Base
  belongs_to :user, :foreign_key => "from_user_id"

  has_many :message_attachments, :dependent => :destroy

  has_many :message_recipients, :dependent => :destroy
  has_many :users, :through => :message_recipients

  has_and_belongs_to_many :message_folders

  validates :subject, :presence => true
  validates :body,    :presence => true

  # === メッセージが使用可能なフォーマット形式の一覧を配列で返す
  def self.format_types
    return [[I18n.t("sns.text_format_strings.plain"),"plain"],
            [I18n.t("sns.text_format_strings.markdown"), "markdown"],
            [I18n.t("sns.text_format_strings.textile"), "textile"]]
  end

  # === メッセージに関連付く添付ファイルを保存する
  # 保存の実施にはcarrier_waveプラグインが使用されている
  def save_attachments(files)
    return false unless files
    files.each do |file|
      attachment = MessageAttachment.new
      attachment.message = self
      attachment.filename = file.original_filename

      if File.extname(file.original_filename) =~ /\.(jpe?g|gif|png)\z/i
        # 画像
        attachment.attachment_file = file
        attachment.content_type = file.content_type
        attachment.size = file.size
      else
        # 画像以外
        attachment.attachment_file = nil
        attachment.content_type = "application/octet-stream"
        attachment.size = 0
      end

      attachment.save

      # 画像以外の場合は、この時点でファイルが保存されていないので、明示的に保存しなければならない
      if attachment.attachment_file.blank?
        target_dir = File.join(MessageAttachmentUploader::DIR, attachment.id.to_s)
        FileUtils.mkdir(target_dir) unless File.exist?(target_dir)
        File.open(File.join(target_dir, attachment.filename), "wb") { |f| f.print File.read(file.tempfile) }
      end
    end
  end

  # === メッセージの受信者情報を設定する
  # 実在しないユーザーは登録できないようになっている。
  def set_recipients(to_list, cc_list = "")
    to_users = check_recipient_list(to_list)
    cc_users = check_recipient_list(cc_list)

    # ToもしくはCcに非実在ユーザーが指定された場合はfalseを返す
    return false unless to_users
    return false unless cc_users

    # ToもしくはCcに宛先指定が一つも無い場合はfalseを返す
    return false if to_users.empty? && cc_users.empty?

    to_users.each do |user|
      add_recipient(user, "to")
    end

    cc_users.each do |user|
      add_recipient(user, "cc")
    end

    (to_users | cc_users).each do |user|
      user.message_rules.each do |rule|
        rule.execute_rule(self)
      end
    end
  end

  # === メッセージに設定されている宛先をカンマ区切りの文字列として取得する
  def to_addrs
    addrs_str = self.message_recipients.where(:recipient_type => "to").collect do |mr|
      mr.user.nick_name  if mr.user.profile
    end
    return addrs_str.join(", ")
  end

  # === メッセージに設定されているCc:をカンマ区切りの文字列として取得する
  def cc_addrs
    addrs_str = self.message_recipients.where(:recipient_type => "cc").collect do |mr|
      mr.user.nick_name if mr.user.profile
    end
    return addrs_str.join(", ")
  end

  # === メッセージに既読フラグを立てる
  def set_read_flag(user)
    mr = get_recipient(user)
    unless mr.read_flag
      mr.read_flag = true
      mr.save
    end
  end

  # === 返信用の本文情報などを設定する
  # TODO: 引用符やらタイトルの返信ヘッダやら、設定ファイルからとれるようにすること
  def set_reply_fields
    self.subject = "Re: #{self.subject}"
    org_body = self.body
    self.body = ""
    org_body.each_line do |line|
      self.body += "> " + line
    end
    self.body = self.body.chomp + "\n\n"
  end

  # 引数で指定されたユーザーオブジェクトが宛先（もしくはCc:）に含まれていれば
  # その情報を返す。含まれていなければnilを返す
  def get_recipient(user)
    return self.message_recipients.where(:user_id => user.id).first
  end

  # === メッセージの再送時に、前と同じサブジェクトと本文を設定する
  def set_attr(org_message)
    self.subject = org_message.subject
    self.body = org_message.body
    return true
  end


  private

  # === 引数で指定された文字列を分解し、ユーザーオブジェクトの配列にして
  # 返す。ただし、1つでも非実在のユーザー名があった場合はfalseを返す
  def check_recipient_list(list)
    users = []
    list.split(/\s*,\s*/).each do |name|
      user = User.where(:nick_name => name).first
      if user
        users << user
      else
        return false
      end
    end
    return users
  end

  # === 第一引数で指定されたユーザーのログイン名を第二引数で指定する宛先種別
  # （To: もしくは Cc:）で宛先リストに追加する
  def add_recipient(user, type)
    recipient = MessageRecipient.new(:recipient_type => type)
    recipient.user = user
    recipient.message = self
    if recipient.save
      return true
    else
      return false
    end
  end
end

